fix(pytket decoder): Panic on repeated registers in pytket decoded output#1445
fix(pytket decoder): Panic on repeated registers in pytket decoded output#1445
Conversation
| node, | ||
| hugr, | ||
| // Output bits use new registers, so don't reuse any input bits. | ||
| EmitCommandOptions::new().reuse_bits(|_| vec![]), |
There was a problem hiding this comment.
Drive-by: The classical expression emitter was re-using the input bits to the node instead of using a separate output bit register.
There was a problem hiding this comment.
Yeah this looks like it might even have been the bigger fix?? Do we have a test that covers just this?
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1445 +/- ##
==========================================
+ Coverage 79.60% 80.03% +0.43%
==========================================
Files 155 155
Lines 20335 20333 -2
Branches 19345 19343 -2
==========================================
+ Hits 16187 16274 +87
+ Misses 3188 3098 -90
- Partials 960 961 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
204bbf7 to
c8ea134
Compare
acl-cqc
left a comment
There was a problem hiding this comment.
Thanks, @aborgna-q - I think there are some fairly significant improvements/fixes in, so keen to get this in :). I think a couple of comments are significant (PR title/panicking) but mostly just neatness/comprehension so I'll approve rightaway :-)
| .first() | ||
| .into_iter() | ||
| .flat_map(|bit| self.bit_wires(bit)); | ||
| let qubit_candidates = if reg_count.qubits > 0 && !qubit_args.is_empty() { |
There was a problem hiding this comment.
You definitely could reduce the diff - IIUC this is
let qubit_candidates = qubit_args
.first()
.filter(|_| reg_count.qubits > 0) // the only new bit
.into_iter()
.flat_map(|qb| self.qubit_wires(qb));
and same for bit_candidates. TBH I think this is simpler, and avoids Either which is a bit nasty IMHO.
| encoder.emit_node_command( | ||
| node, | ||
| hugr, | ||
| // Output bits use new registers, so don't reuse any input bits. |
There was a problem hiding this comment.
super-nit: consider assigning this to a variable first (called output_bits, thus shortening the comment?)
| for qubit in encoded_info.output_qubits.iter() { | ||
| let id = self.wire_tracker.tracked_qubit_for_register(qubit)?; | ||
| qubits.insert(id.clone()); | ||
| qubits.push(id.clone()); |
There was a problem hiding this comment.
The PR title is "Panic on repeated registers". I don't see anything that would panic if the same qubit was pushed more than once - TBH it seems to me that "repeated registers" for qubits is a fairly serious error (linearity violation), so panicking sounds like a good thing to do?
(Not sure whether "registers" means "qubits", "bits" or both - panicking on repeated bits sounds an odd thing to do if you are from any background other than pytket 😉 😁 but you might want to)
If the PR title is wrong and we don't panic, please update it ;-), maybe something about bit registers if it doesn't apply to qubits.
| // Add any additional qubits or bits we have seen, without modifying the | ||
| // order of the qubits already there. | ||
|
|
||
| // Add any additional qubits or bits we have seen but haven't added to the list. |
| .hugr_mut() | ||
| .connect(wire.node(), wire.source(), node, input_idx); | ||
| } | ||
| input_bits.iter().take(op_input_count.bits).for_each(|b| { |
There was a problem hiding this comment.
I am not quite sure why removing this is the right thing to do - it sounds plausible, I think I'm happy to trust you ;-).
Are there still calls to mark_bit_outdated elsewhere or can we remove it?
| } | ||
|
|
||
| /// A simple circuit with some preset input and output bit registers, | ||
| /// including multiple outputs for the same register. |
There was a problem hiding this comment.
| /// including multiple outputs for the same register. | |
| /// including multiple outputs of the same register. |
??
| node, | ||
| hugr, | ||
| // Output bits use new registers, so don't reuse any input bits. | ||
| EmitCommandOptions::new().reuse_bits(|_| vec![]), |
There was a problem hiding this comment.
Yeah this looks like it might even have been the bigger fix?? Do we have a test that covers just this?
| // Convert the wire type, if needed. | ||
| let wire_data = &self.wires[&wire]; | ||
| let new_wire = config.transform_typed_value(wire, wire_data.ty(), ty, builder)?; | ||
| let found_wire_type = wire_data.ty(); |
There was a problem hiding this comment.
not clear why you've changed this, you're not using found_wire_type anywhere you weren't before AFAICS. If you're intending the name to be an improvement then you should probably rename wire_data to found_wire instead?
Fix an edge case where we extracted a hugr from a pytket circuit, and declared multiple output ports to have the same bit register.
Also cleans up a bit of the logic that handled consumed bit wires, to avoid marking them as outdated if they can still be used by other operations.